#pragma once

#include "LockGuard.hpp"
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <pthread.h>
#include <fstream>

const std::string logname = "log.txt";

bool gIsSave = false;

// 1.日志等级
enum Level
{
	DEBUG = 0,
	INFO,
	WARNING,
	ERROR,
	FATAL
};
std::string LevelToString(int level)
{
	switch (level)
	{
	case Level::DEBUG:
		return "DEBUG";
	case Level::INFO:
		return "INFO";
	case Level::WARNING:
		return "WARNING";
	case Level::ERROR:
		return "ERROR";
	case Level::FATAL:
		return "ERROR";
	default:
		return "UNKNOWN";
	}
}

void SaveFile(const std::string &filename, const std::string &message)
{
	std::ofstream out(filename, std::ios::app);
	if (!out.is_open())
		return;
	out << message;
	out.close();
}

std::string GetTimeString()
{
	time_t cur_time = time(nullptr);
	struct tm *format_time = localtime(&cur_time);
	if (format_time == nullptr)
		return "None";
	char time_buffer[1024];
	snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",
			 format_time->tm_year + 1900,
			 format_time->tm_mon + 1,
			 format_time->tm_mday,
			 format_time->tm_hour,
			 format_time->tm_min,
			 format_time->tm_sec);
	return time_buffer;
}

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

// 2.日志格式
// 日志等级 时间代码所在文件名/行数 日志的内容
void LogMessage(std::string filename, int line, bool issave, int level, const char *format, ...)
{
	std::string levelstr = LevelToString(level);
	std::string timestr = GetTimeString();
	pid_t selfid = getpid();

	char buffer[1024];
	va_list arg;
	va_start(arg, format);
	vsnprintf(buffer, sizeof(buffer), format, arg);
	va_end(arg);
	LockGuard lockguard(&lock);
	std::string message = "[" + timestr + "]" + "[" + levelstr + "]" +
						  "[" + std::to_string(selfid) + "]" +
						  "[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";
	if (!issave)
	{
		std::cout << message;
	}
	else
	{
		SaveFile(logname, message);
	}
}

//__VA_ARGS__可变参数宏替换
// ##表示如果可变参数为空，则##后面的内容被忽略
// 宏标准写法
#define LOG(level, format, ...)                                                \
	do                                                                         \
	{                                                                          \
		LogMessage(__FILE__, __LINE__, gIsSave, level, format, ##__VA_ARGS__); \
	} while (0)
#define EnableFile()    \
	do                  \
	{                   \
		gIsSave = true; \
	} while (0)
#define EnableScreen()   \
	do                   \
	{                    \
		gIsSave = false; \
	} while (0)
